﻿using System;
using System.Collections.Generic;
using System.Text;

namespace DBSourceToolsLib
{
    public class SourceDatabase : DatabaseEx
    {
        private SysObjects.SysObjects m_SysObjects;
        private EventHandler<ProgressEventArgs> m_localHandler;
        DBDiff.Schema.SQLServer.Generates.Generate m_SourceGenerate = new DBDiff.Schema.SQLServer.Generates.Generate();
        private DBDiff.Schema.SQLServer.Generates.Generate m_TargetGenerate
            = new DBDiff.Schema.SQLServer.Generates.Generate();
        public DBDiff.Schema.SQLServer.Generates.Model.Database TargetDatabase;
        public DBDiff.Schema.SQLServer.Generates.Model.Database OriginalTargetDatabase;
        public DBDiff.Schema.SQLServer.Generates.Model.Database DiffSourceDatabase;
        public DBDiff.Schema.SQLServer.Generates.Model.Database OriginalSourceDatabase;
        private DBDiff.Schema.SQLServer.Generates.Model.Database SourceClone;
        private string m_DiffScript = "";

        public string DiffScript
        {
            get { return m_DiffScript; }
        }

        public SysObjects.SysObjects SysObjects
        {
            get { return m_SysObjects; }
            set { m_SysObjects = value; }
        }
        
        private DatabaseScriptOptions m_ScriptOptions;

        public DatabaseScriptOptions ScriptOptions
        {
            get { return m_ScriptOptions; }
            set { m_ScriptOptions = value; }
        }
 
        private List<TargetDatabase> m_TargetDatabases = new List<TargetDatabase>();

        public List<TargetDatabase> TargetDatabases
        {
            get { return m_TargetDatabases; }
        }

        public SourceDatabase(DBConnectionLib.Database oDatabase, bool bCreateScriptOptions) : base(oDatabase, false)
        {
            m_SysObjects = new DBSourceToolsLib.SysObjects.SysObjects(this, this.BaseDirectory);
            m_ScriptOptions = new DatabaseScriptOptions(this, bCreateScriptOptions);
            NeedsWriteTargets = oDatabase.NeedsWriteTargets;
        }

        public void AddTargetDatabase(DBConnectionLib.Database oDatabase, bool bCreateDropScripts)
        {
            TargetDatabase oNewTarget = new TargetDatabase(oDatabase, this);
            if (bCreateDropScripts)
                oNewTarget.AddDropAndCreateScript(this);
            m_TargetDatabases.Add(oNewTarget);

        }

        public void RemoveTargetDatabase(string strDatabaseName)
        {
            int iFoundIdx = -1;
            string strBaseDirectory = null;
            for( int i = 0; i < TargetDatabases.Count; i++)
            {
                TargetDatabase oTarget = TargetDatabases[i];
                if (strDatabaseName.CompareTo(oTarget.NickName) == 0)
                {
                    iFoundIdx = i;
                    strBaseDirectory = oTarget.BaseDirectory;
                }
            }
            if (iFoundIdx > -1)
            {
                DBSourceToolsLib.FileUtils oUtils = new FileUtils();
                oUtils.DeleteFilesInDirRecursive(strBaseDirectory);
                TargetDatabases.RemoveAt(iFoundIdx);
            }

        }

        internal void ClearFilesFromDisk()
        {
            DirHelper oDirHelper = new DirHelper();
            oDirHelper.DeleteFilesInDir(this.BaseDirectory + "\\Tables");
            oDirHelper.DeleteFilesInDir(this.BaseDirectory + "\\Procs");
            oDirHelper.DeleteFilesInDir(this.BaseDirectory + "\\Functions");
            oDirHelper.DeleteFilesInDir(this.BaseDirectory + "\\Views");
            oDirHelper.DeleteFilesInDir(this.BaseDirectory + "\\DataTypes");
            oDirHelper.DeleteFilesInDir(this.BaseDirectory + "\\Schemas");
            oDirHelper.DeleteFilesInDir(this.BaseDirectory + "\\XmlSchemas");
            oDirHelper.DeleteFilesInDir(this.BaseDirectory + "\\Users");
            oDirHelper.DeleteFilesInDir(this.BaseDirectory + "\\Roles");
            oDirHelper.DeleteFilesInDir(this.BaseDirectory + "\\Synonyms");

        }

        public void Test()
        {
            //this.GetSmoDatabase().Users[0].EnumRoles();
        }

        internal void CompareDatabase(EventHandler<ProgressEventArgs> localHandler, string m_Params)
        {
            m_localHandler = localHandler;

            DatabaseEx oTargetDb = UserSettings.Instance().DatabaseProject.GetDatabaseEx(m_Params);

            m_SourceGenerate.ConnectionString = this.ConnectionString;
            m_TargetGenerate.ConnectionString = oTargetDb.ConnectionString;

            m_SourceGenerate.Options = new DBDiff.Schema.SQLServer.Generates.Options.SqlOption();
            m_SourceGenerate.Options.Comparison.IgnoreWhiteSpacesInCode = true;
            m_TargetGenerate.Options = new DBDiff.Schema.SQLServer.Generates.Options.SqlOption();
            m_TargetGenerate.Options.Comparison.IgnoreWhiteSpacesInCode = true;

            m_SourceGenerate.OnProgress += new DBDiff.Schema.Events.ProgressEventHandler.ProgressHandler(oSourceSql_OnProgress);
            m_TargetGenerate.OnProgress += new DBDiff.Schema.Events.ProgressEventHandler.ProgressHandler(m_TargetSql_OnProgress);

            OriginalSourceDatabase = m_SourceGenerate.Process();
            DiffSourceDatabase = m_SourceGenerate.Process();
            TargetDatabase = m_TargetGenerate.Process();
            OriginalTargetDatabase = m_TargetGenerate.Process();
            SourceClone = (DBDiff.Schema.SQLServer.Generates.Model.Database)DiffSourceDatabase.Clone(null);

            TargetDatabase 
                = DBDiff.Schema.SQLServer.Generates.Generate.Compare(
                    TargetDatabase, DiffSourceDatabase);

            m_DiffScript = this.TargetDatabase.ToSqlDiff().ToSQL();
            DiffSourceDatabase = SourceClone;
            
        }

        void m_TargetSql_OnProgress(DBDiff.Schema.Events.ProgressEventArgs e)
        {
            if (m_localHandler != null)
                m_localHandler(this, new ProgressEventArgs(e.Progress, m_TargetGenerate.MaxValue,
                    e.Message));
        }

        void oSourceSql_OnProgress(DBDiff.Schema.Events.ProgressEventArgs e)
        {
            if (m_localHandler != null)
                m_localHandler(this, new ProgressEventArgs(e.Progress, m_SourceGenerate.MaxValue,
                    e.Message));
        }

        internal void LoadPatchesFromDisk()
        {
            foreach (TargetDatabase oTargetDatabase in m_TargetDatabases)
                oTargetDatabase.LoadPatchesFromDisk();
        }

        public Composite.DBComposite GetDBComposite()
        {

            Composite.DBComposite oDBComposite = new Composite.DBComposite(this.NickName, this.NickName,
                Composite.DBCompositeType.Database,
                new Composite.TreeNodeTag(this.NickName, "Database", null, null));

            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.Table) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("Tables","Tables",
                    Composite.DBCompositeType.Tables,
                    new Composite.TreeNodeTag(this.NickName, "Tables", null, null));
                foreach (DBSourceToolsLib.SysObjects.SOTable oSysObject in SysObjects.Tables)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }

            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.View) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("Views","Views",
                    Composite.DBCompositeType.Views,
                    new Composite.TreeNodeTag(this.NickName, "Views", null, null));
                foreach (DBSourceToolsLib.SysObjects.SysObject oSysObject in SysObjects.Views)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }

            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.Proc) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("Procedures","Procedures",
                    Composite.DBCompositeType.Procs,
                    new Composite.TreeNodeTag(this.NickName, "Procedures", null, null));
                foreach (DBSourceToolsLib.SysObjects.SysObject oSysObject in SysObjects.Procs)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }

            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.Function) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("Functions","Functions",
                    Composite.DBCompositeType.Functions,
                    new Composite.TreeNodeTag(this.NickName, "Functions", null, null));
                foreach (DBSourceToolsLib.SysObjects.SysObject oSysObject in SysObjects.Functions)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }

            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.DataType) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("DataTypes","DataTypes",
                    Composite.DBCompositeType.DataTypes,
                    new Composite.TreeNodeTag(this.NickName, "DataTypes", null, null));
                foreach (DBSourceToolsLib.SysObjects.SysObject oSysObject in SysObjects.DataTypes)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }

            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.TableType) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("TableTypes","TableTypes",
                    Composite.DBCompositeType.Table_Types,
                    new Composite.TreeNodeTag(this.NickName, "TableTypes", null, null));
                foreach (DBSourceToolsLib.SysObjects.SysObject oSysObject in SysObjects.TableTypes)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }


            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.Schema) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("Schemas","Schemas",
                    Composite.DBCompositeType.Schemas,
                    new Composite.TreeNodeTag(this.NickName, "Schemas", null, null));
                foreach (DBSourceToolsLib.SysObjects.SysObject oSysObject in SysObjects.Schemas)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }


            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.XmlSchema) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("XmlSchemas","XmlSchemas",
                    Composite.DBCompositeType.XmlSchemas,
                    new Composite.TreeNodeTag(this.NickName, "XmlSchemas", null, null));
                foreach (DBSourceToolsLib.SysObjects.SysObject oSysObject in SysObjects.XmlSchemas)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }

            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.User) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("Users","Users",
                    Composite.DBCompositeType.Users,
                    new Composite.TreeNodeTag(this.NickName, "Users", null, null));
                foreach (DBSourceToolsLib.SysObjects.SysObject oSysObject in SysObjects.Users)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }

            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.Role) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("Roles","Roles",
                    Composite.DBCompositeType.Roles,
                    new Composite.TreeNodeTag(this.NickName, "Roles", null, null));
                foreach (DBSourceToolsLib.SysObjects.SysObject oSysObject in SysObjects.Roles)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }

            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.Trigger) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("Triggers","Triggers",
                    Composite.DBCompositeType.Triggers,
                    new Composite.TreeNodeTag(this.NickName, "Triggers", null, null));
                foreach (DBSourceToolsLib.SysObjects.SysObject oSysObject in SysObjects.Triggers)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }



            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.Querie) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("Queries","Queries",
                    Composite.DBCompositeType.Queries,
                    new Composite.TreeNodeTag(this.NickName, "Queries", null, null));
                foreach (DBSourceToolsLib.SysObjects.SysObject oSysObject in SysObjects.Queries)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }

            if (SysObjects.Count(DBSourceToolsLib.SysObjects.SysObjectType.Synonym) > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("Synonyms", "Synonyms",
                    Composite.DBCompositeType.Synonym,
                    new Composite.TreeNodeTag(this.NickName, "Synonyms", null, null));
                foreach (DBSourceToolsLib.SysObjects.SysObject oSysObject in SysObjects.Synonyms)
                    oComposite.Add(oSysObject.GetDBComposite());
                oDBComposite.Add(oComposite);
            }

            Composite.DBComposite oDependencyComposite = new Composite.DBComposite("Dependency Tree","Dependency Tree",
                Composite.DBCompositeType.Dependancy,
                new Composite.TreeNodeTag(this.NickName, "Dependency Tree", null, null));
            oDBComposite.Add(oDependencyComposite);

            if (this.TargetDatabases.Count > 0)
            {
                Composite.DBComposite oComposite = new Composite.DBComposite("Deployment Targets","Deployment Targets",
                    Composite.DBCompositeType.Deployment_Targets,
                    new Composite.TreeNodeTag(this.NickName, "Deployment Targets", null, null));

                foreach (TargetDatabase oTargetDatabase in this.TargetDatabases)
                {
                    oComposite.Add(oTargetDatabase.GetDBComposite());
                }
                oDBComposite.Add(oComposite);

            }

            return oDBComposite;
        }
    }
}
